﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using MovieDB.Common.Exceptions;
using MovieDB.Data.Entities;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Linq;

namespace MovieDB.Data.Repositories
{
    public class Repository<T> : IRepository<T>
        where T: BaseEntity
    {
        private readonly IUnitOfWork _unitOfWork;

        public Repository(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }

        public void Save(T entity)
        {
            try
            {
                entity.LastUpdate = DateTime.Now;
                _unitOfWork.Session.SaveOrUpdate(entity);
                _unitOfWork.Session.Flush(); // flush here in order to check for various constraint violations. TransactionScope will handle the commit / rollback
            }
            catch (Exception ex)
            {
                // TODO: log
                ExceptionHelper.HandleException(ex);
            }
        }

        public void Delete(T entity)
        {
            _unitOfWork.Session.Delete(entity);
            _unitOfWork.Session.Flush(); // flush here in order to check for various constraint violations. TransactionScope will handle the commit / rollback
        }

        public T FindById(int id)
        {
            return FindBy(x => x.Id == id, false);
        }

        public T FindBy(Expression<Func<T, bool>> condition)
        {
            return FindBy(condition, true);
        }

        public T FindBy(Expression<Func<T, bool>> condition, bool defaultIfEmpty)
        {
            var queryable = _unitOfWork.Session.Linq<T>();
            if (defaultIfEmpty)
            {
                return queryable.FirstOrDefault(condition);
            }
            else
            {
                return queryable.First(condition);
            }
        }

        public List<T> FindManyBy(Expression<Func<T, bool>> condition)
        {
            return _unitOfWork.Session.Linq<T>()
                .Where(condition)
                .ToList();
        }
    }
}
